home *** CD-ROM | disk | FTP | other *** search
/ LiquidLibrary 2005 September / LiquidLibrary 2005 Sep - Disc 1.iso / pc / Portfolio Browser / Filters / PDF / LIB / pdf_sec.ps < prev    next >
Text File  |  2003-01-03  |  10KB  |  362 lines

  1. %   Copyright (C) 1996-1998 Geoffrey Keating. 
  2. %    Copyright (C) 2001 Artifex Software, Inc.
  3. % This file may be freely distributed with or without modifications,
  4. % so long as modified versions are marked as such and copyright notices are
  5. % not removed.
  6.  
  7. % $RCSfile$ $Revision$
  8. % Implementation of security hooks for PDF reader.
  9.  
  10. % This file contains the procedures that have to take encryption into
  11. % account when reading a PDF file. It replaces the stub version of this
  12. % file that is shipped with GhostScript. It requires GhostScript 7.01
  13. % or later.
  14.  
  15. % Documentation for using this file is available at
  16. % http://www.ozemail.com.au/%7Egeoffk/pdfencrypt/
  17.  
  18. % Modified by Alex Cherepanov to work with GS 6.60 and higher.
  19. % New versions of GS require explicit checks for /true , /false, and /null
  20. % in .decpdfrun . This fix is backward-compatible.
  21.  
  22. % Modified by Raph Levien and Ralph Giles to use the new C
  23. % implementations of md5 and arcfour in ghostscript 7.01, and to
  24. % be compatible with PDF 1.4 128-bit encryption.
  25.  
  26. /.setlanguagelevel where { pop 2 .setlanguagelevel } if
  27. .currentglobal true .setglobal
  28. /pdfdict where { pop } { /pdfdict 100 dict def } ifelse
  29. pdfdict begin
  30.  
  31. % Older ghostscript versions do not have .pdftoken, so we use 'token' instead.
  32. /.pdftoken where { pop } { /.pdftoken /token load def } ifelse
  33.  
  34. % take a stream and arc4 decrypt it.
  35. % <stream> <key> arc4decodefilter <stream>
  36. /arc4decodefilter {
  37.   1 dict begin
  38.   /Key exch def
  39.   currentdict end /ArcfourDecode filter
  40. } bind def
  41.  
  42. % <ciphertext> <key> arc4decode <plaintext>
  43. /arc4decode {
  44.   %(key: ) print dup == (ct: ) print 1 index ==
  45.   1 index length 0 eq {
  46.     pop
  47.   } {
  48.     1 index length string 3 1 roll arc4decodefilter exch readstring pop
  49.   } ifelse
  50. } bind def
  51.  
  52. /md5 {
  53.   16 string dup /MD5Encode filter dup 4 3 roll writestring closefile
  54. } bind def
  55.  
  56. /pdf_padding_string
  57.    <28bf4e5e4e758a41 64004e56fffa0108
  58.     2e2e00b6d0683e80 2f0ca9fe6453697a>
  59. def
  60.  
  61. % Pad a key out to 32 bytes.
  62. /pdf_pad_key {        % <key> pdf_pad_key <padded key>
  63.   dup length 32 gt { 0 32 getinterval } if
  64.   pdf_padding_string
  65.   0 32 3 index length sub getinterval
  66.   concatstrings
  67. } bind def
  68.  
  69. /pdf_xorbytes {      % <iter-num> <key> pdf_xorbytes <xored-key>
  70.   dup length dup string
  71.   exch 1 sub 0 1 3 2 roll {
  72.     % <iter-num> <key> <new-key> <byte-num>
  73.     dup 3 index exch get 4 index xor
  74.     % <iter-num> <key> <new-key> <byte-num> <byte>
  75.     3 copy put pop pop
  76.   } for
  77.   3 1 roll pop pop
  78. } bind def
  79.  
  80. % Get length of encryption key in bytes
  81. /pdf_key_length {    % pdf_key_length <key_length>
  82.   Trailer /Encrypt oget /Length knownoget { -3 bitshift } { 5 } ifelse
  83. } bind def
  84.  
  85. % Algorithm 3.2
  86. /pdf_compute_encryption_key {  % <password> pdf_compute_encryption_key <key>
  87.   % Step 1.
  88.   pdf_pad_key
  89.  
  90.   % Step 2, 3.
  91.   Trailer /Encrypt oget dup /O oget
  92.   % <padded-key> <encrypt> <O>
  93.  
  94.   % Step 4.
  95.   exch /P oget 4 string exch
  96.   2 copy 255 and 0 exch put
  97.   2 copy -8 bitshift 255 and 1 exch put
  98.   2 copy -16 bitshift 255 and 2 exch put
  99.   2 copy -24 bitshift 255 and 3 exch put pop
  100.   % <padded-key> <O> <P>
  101.  
  102.   % Step 5.
  103.   Trailer /ID oget 0 oget
  104.   3 { concatstrings } repeat md5
  105.  
  106.   % Step 6.
  107.   Trailer /Encrypt oget /R oget 3 eq {
  108.      50 { md5 } repeat
  109.   } if
  110.  
  111.   % Step 7.
  112.   0 pdf_key_length getinterval
  113. } bind def
  114.  
  115. % Algorithm 3.4
  116. /pdf_gen_user_password_R2 { % <filekey> pdf_gen_user_password_R2 <U>
  117.  
  118.   % Step 2.
  119.   pdf_padding_string exch arc4decode
  120. } bind def
  121.  
  122. % Algorithm 3.5
  123. /pdf_gen_user_password_R3 { % <filekey> pdf_gen_user_password_R3 <U>
  124.  
  125.   % Step 2.
  126.   pdf_padding_string
  127.  
  128.   % Step 3.
  129.   Trailer /ID oget 0 oget
  130.   concatstrings md5
  131.  
  132.   % Step 4.
  133.   1 index arc4decode
  134.  
  135.   % Step 5.
  136.   1 1 19 {
  137.     2 index pdf_xorbytes arc4decode
  138.   } for
  139.   exch pop
  140.  
  141. } bind def
  142.  
  143. /pdf_gen_user_password { % <password> pdf_gen_user_password <filekey> <U>
  144.   % common Step 1 of Algorithms 3.4 and 3.5.
  145.   pdf_compute_encryption_key dup
  146.  
  147.   Trailer /Encrypt oget
  148.  
  149.   /R oget dup 2 eq {
  150.     pop pdf_gen_user_password_R2
  151.   } {
  152.     dup 3 eq {
  153.       pop pdf_gen_user_password_R3
  154.     } {
  155.       (****This file uses an unknown standard security handler revision: )
  156.       print == flush
  157.       /pdf_check_user_password cvx /undefined signalerror
  158.     } ifelse
  159.   } ifelse
  160. } bind def
  161.  
  162. % Algorithm 3.6
  163. /pdf_check_user_password { % <password> pdf_check_user_password <filekey> true
  164.                            % <password> pdf_check_user_password false
  165.   pdf_gen_user_password
  166.  
  167.   Trailer /Encrypt oget /U oget
  168.  
  169.   0 2 index length getinterval eq {
  170.     true
  171.   } {
  172.     pop false
  173.   } ifelse
  174. } bind def
  175.  
  176. % Compute an owner key, ie the result of step 4 of Algorithm 3.3
  177. /pdf_owner_key % <password> pdf_owner_key <owner-key>
  178. {
  179.   % Step 1.
  180.   pdf_pad_key
  181.  
  182.   % Step 2.
  183.   md5
  184.  
  185.   % 3.3 Step 3.
  186.   Trailer /Encrypt oget /R oget 3 eq {
  187.     50 { md5 } repeat
  188.   } if
  189.  
  190.   % Step 4.
  191.   0 pdf_key_length getinterval
  192. } bind def
  193.  
  194. % Algorithm 3.7
  195. /pdf_check_owner_password { % <password> pdf_check_owner_password <filekey> true
  196.                             % <password> pdf_check_owner_password false
  197.   % Step 1.
  198.   pdf_owner_key
  199.  
  200.   % Step 2.
  201.   Trailer /Encrypt oget dup /O oget 2 index arc4decode
  202.   % <encryption-key> <encrypt-dict> <decrypted-O>
  203.  
  204.   % Step 3.
  205.   exch /R oget 3 eq {
  206.     1 1 19 {
  207.       2 index pdf_xorbytes arc4decode
  208.     } for
  209.   } if
  210.   exch pop
  211.   % <result-of-step-3>
  212.  
  213.   pdf_check_user_password
  214. } bind def
  215.  
  216. % Process the encryption information in the Trailer.
  217. /pdf_process_Encrypt {
  218.   Trailer /Encrypt oget
  219.   /Filter oget /Standard eq not {
  220.     (****This file uses an unknown security handler.\n) print flush
  221.     /pdf_process_Encrypt cvx /undefined signalerror
  222.   } if
  223.   () pdf_check_user_password
  224.   {
  225.     /FileKey exch def
  226.   } {
  227.     /PDFPassword where {
  228.        pop PDFPassword pdf_check_user_password
  229.        {
  230.          /FileKey exch def
  231.        } {
  232.          PDFPassword pdf_check_owner_password
  233.          {
  234.            /FileKey exch def
  235.          } {
  236.            (****Password did not work.\n) print flush
  237.        /pdf_process_Encrypt cvx /invalidfileaccess signalerror
  238.          } ifelse
  239.        } ifelse
  240.     } {
  241.       (****This file requires a password for access.\n) print flush
  242.       /pdf_process_Encrypt cvx /invalidfileaccess signalerror
  243.     } ifelse
  244.   } ifelse
  245.  
  246. %   Trailer /Encrypt oget /P oget 4 and 0 eq #? and
  247. %    { (****This owner of this file has requested you do not print it.\n)
  248. %      print flush
  249. %      /pdf_process_Encrypt cvx /invalidfileaccess signalerror
  250. %    }
  251. %   if
  252. } bind def
  253.  
  254. % Calculate the key used to decrypt an object (to pass to .decpdfrun or
  255. % put into a stream dictionary).
  256. /computeobjkey    % <object#> <generation#> computeobjkey <keystring>
  257. {
  258.   exch
  259.   FileKey length 5 add string
  260.   dup 0 FileKey putinterval
  261.   exch
  262.         % stack:  gen# string obj#
  263.     2 copy 255 and FileKey length exch put
  264.     2 copy -8 bitshift 255 and FileKey length 1 add exch put
  265.     2 copy -16 bitshift 255 and FileKey length 2 add exch put
  266.   pop exch
  267.     2 copy 255 and FileKey length 3 add exch put
  268.     2 copy -8 bitshift 255 and FileKey length 4 add exch put
  269.   pop md5 0 FileKey length 5 add 2 index length min getinterval
  270. } bind def
  271.  
  272. % As .pdfrun, but decrypt strings with key <key>.
  273. /.decpdfrun            % <file> <keystring> <opdict> .decpdfrun -
  274.  {    % Construct a procedure with the file, opdict and key bound into it.
  275.    2 index cvlit mark mark 5 2 roll
  276.     { .pdftoken not { (%%EOF) cvn cvx } if
  277.       dup xcheck
  278.        { DEBUG { dup == flush } if
  279.      3 -1 roll pop
  280.      2 copy .knownget
  281.       { exch pop exch pop exec
  282.           }
  283.       { exch pop
  284.             dup /true eq
  285.               { pop //true
  286.               }
  287.               { dup /false eq
  288.                   { pop //false 
  289.                   }
  290.                   { dup /null eq
  291.                       { pop //null
  292.                       }
  293.                       { (%stderr) (w) file
  294.                     dup (****************Unknown operator: ) writestring
  295.                     dup 3 -1 roll .writecvs dup (\n) writestring flushfile
  296.                       }
  297.                     ifelse
  298.                   }
  299.                 ifelse
  300.               }
  301.             ifelse
  302.       }
  303.      ifelse
  304.        }
  305.        { exch pop DEBUG { dup ==only ( ) print flush } if
  306.      dup type /stringtype eq
  307.       { 1 index arc4decode
  308.         DEBUG { (%Decrypted: ) print dup == flush } if
  309.       }
  310.      if
  311.      exch pop
  312.        }
  313.       ifelse
  314.     }
  315.    aload pop .packtomark cvx
  316.    /loop cvx 2 packedarray cvx
  317.     { stopped /PDFsource } aload pop
  318.    PDFsource
  319.     { store { stop } if } aload pop .packtomark cvx 
  320.    /PDFsource 3 -1 roll store exec
  321.  } bind def
  322.  
  323. % Run the code to resolve an object reference.
  324. /pdf_run_resolve
  325.  { /FileKey where
  326.     { pop
  327.       2 copy computeobjkey dup 4 1 roll
  328.       PDFfile exch resolveopdict .decpdfrun
  329.       dup dup dup 5 2 roll
  330.     % stack: object object key object object
  331.       xcheck exch type /dicttype eq and
  332.        { /StreamKey exch put }
  333.        { pop pop }
  334.       ifelse
  335.     }
  336.     { PDFfile resolveopdict .pdfrun }
  337.    ifelse
  338.  } bind def
  339.  
  340. % Prefix a decryption filter to a stream if needed.
  341. % Stack: readdata? dict parms file/string filternames
  342. % (both before and after).
  343. /pdf_decrypt_stream
  344.  { 3 index /StreamKey known
  345.    {
  346.       exch 
  347.     % Stack: readdata? dict parms filternames file/string
  348.       3 index /Length oget
  349.       dup 0 eq {
  350.     % Handle Length=0 case specially to avoid SubFileDecode semantics
  351.         pop pop ()
  352.       } {
  353.         () /SubFileDecode filter
  354.       } ifelse
  355.       3 index /StreamKey get arc4decodefilter
  356.       exch
  357.    } if
  358.  } bind def
  359.  
  360. end            % pdfdict
  361. .setglobal
  362.